/* -*- Mode: c; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
  RefObject (http://code.google.com/p/refobject/)
  Copyright (C) 2010-2011 MIURA Shirow (sharow)
*/

#include "RefBaseInternal.h"
#include "RefVoidPtrInternal.h"

typedef struct {
    void *mVoidPtr;
    RefVoidPtrDestructor mDestructorProc;
    RefObject *mRefAllocator;
} RefVoidPtr;

static RefTypeObject *gVoidPtrTypeObject = NULL;

RefTypeObject **
RefVoidPtr_GetTypeObject(void)
{
    return &gVoidPtrTypeObject;
}

int
RefVoidPtr_IsValid(RefObject *aRefObject)
{
    return (RefObject_GetTypeObject(aRefObject) == &gVoidPtrTypeObject);
}

static void
RefVoidPtr_Destructor(RefObject *aRefObject)
{
    RefVoidPtr *voidptr;
    RefObject *refallocator;
    voidptr = (RefVoidPtr *)RefObject_GetObject(aRefObject);
    if (voidptr->mDestructorProc) {
        voidptr->mDestructorProc(voidptr->mVoidPtr);
    }
    refallocator = voidptr->mRefAllocator;
    RefAllocator_Free(refallocator, aRefObject);
    RefObject_DecRef(refallocator);
}

RefObject *
RefVoidPtr_Create(void *aVoidPtr, RefVoidPtrDestructor aDestructor)
{
    return RefVoidPtr_CreateWithAllocator(aVoidPtr, aDestructor, RefModule_GetSingletonAllocator());
}

RefObject *
RefVoidPtr_CreateWithAllocator(void *aVoidPtr, RefVoidPtrDestructor aDestructor, RefObject *aRefAllocator)
{
    RefObject *refobj;
    RefVoidPtr *voidptr;
    if (aRefAllocator && RefAllocator_IsValid(aRefAllocator)) {
    } else {
        return NULL;
    }
    refobj = RefAllocator_Alloc(aRefAllocator, RefObject_SizeOf() + sizeof(*voidptr));
    voidptr = RefObject_Construct(refobj, &gVoidPtrTypeObject, RefVoidPtr_Destructor);
    voidptr->mVoidPtr = aVoidPtr;
    voidptr->mDestructorProc = aDestructor;
    voidptr->mRefAllocator = aRefAllocator;
    RefObject_IncRef(aRefAllocator);
    return refobj;
}

void *
RefVoidPtr_AsVoidPtr(RefObject *aRefObject)
{
    return ((RefVoidPtr *)RefObject_GetObject(aRefObject))->mVoidPtr;
}
